package com.lengxf.pay.icbc;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.lengxf.pay.common.PayException;
import com.lengxf.pay.common.bean.*;
import com.lengxf.pay.common.config.TransactionType;
import com.lengxf.pay.common.http.HttpParam;
import com.lengxf.pay.common.service.AbstractBasePayService;
import com.lengxf.pay.icbc.bean.base.BaseReq;
import com.lengxf.pay.icbc.bean.base.BaseRes;
import com.lengxf.pay.icbc.bean.payBack.PayBackBase;
import com.lengxf.pay.icbc.bean.payBack.PayBackBizContent;
import com.lengxf.pay.icbc.bean.qr.QrReq;
import com.lengxf.pay.icbc.bean.qr.QrRes;
import com.lengxf.pay.icbc.bean.query.QueryReq;
import com.lengxf.pay.icbc.bean.query.QueryRes;
import com.lengxf.pay.icbc.bean.refund.RefundOrderReq;
import com.lengxf.pay.icbc.bean.refund.RefundOrderRes;
import com.lengxf.pay.icbc.bean.refundQuery.RefundQueryOrderRes;
import com.lengxf.pay.icbc.bean.refundQuery.RefundQueryReq;
import com.lengxf.pay.icbc.config.ICBC_PayConfig;
import com.lengxf.pay.icbc.config.ICBC_TransactionType;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;

/**
 * 农业银行
 * By Lengxf 2023-10-26 11:22:55
 **/
public class ICBC_PayService extends AbstractBasePayService<ICBC_PayConfig> {


    private final static String VERSION_HEADER_NAME = "APIGW-VERSION";
    private final static String VERSION = "v2_20190522";

    public ICBC_PayService(ICBC_PayConfig payConfig) {
        super(payConfig);
    }

    @Override
    public Map<String, Object> query(QueryOrder queryOrder) {
        QueryReq queryReq = new QueryReq(getPayConfig().getMerId(), queryOrder.getOrderNo());
        BaseReq<QueryReq> reqs = new BaseReq<>(getPayConfig(), queryReq);
        QueryRes res = execute(reqs, ICBC_TransactionType.QUERY, QueryRes.class);
        return res.toMap();
    }

    @Override
    public Map<String, Object> refund(RefundOrder refundOrder) {
        RefundOrderReq refundOrderReq = new RefundOrderReq(refundOrder, getPayConfig().getMerId());
        BaseReq<RefundOrderReq> reqs = new BaseReq<>(getPayConfig(), refundOrderReq);
        RefundOrderRes res = execute(reqs, ICBC_TransactionType.REFUND, RefundOrderRes.class);
        return res.toMap();
    }

    @Override
    public Map<String, Object> refundQuery(RefundOrderQuery refundOrderQuery) {
        RefundQueryReq refundQueryReq = new RefundQueryReq(refundOrderQuery, getPayConfig().getMerId());
        BaseReq<RefundQueryReq> reqs = new BaseReq<>(getPayConfig(), refundQueryReq);
        RefundQueryOrderRes res = execute(reqs, ICBC_TransactionType.REFUND_QUERY, RefundQueryOrderRes.class);
        return res.toMap();
    }

    @Override
    public String toPay(PayOrder payOrder) {
        QrReq qrReq = QrReq.buildReqBizContent(payOrder, getPayConfig());
        BaseReq<QrReq> reqs = new BaseReq<>(getPayConfig(), qrReq);
        QrRes res = execute(reqs, ICBC_TransactionType.QR, QrRes.class);
        if (res.isSuccess()) {
            return res.getQrcode();
        }
        throw new PayException(String.format("(工行)获取二维码失败,错误码{ %s },错误信息{ %s }", res.getReturnCode(), res.getReturnMsg()));
    }

    @Override
    public Map<String, Object> payBack(CallBackParam callBackParam) {
        Map<String, String> map = callBackParam.toSignleParameterMap();
        PayBackBase payBackBase = BeanUtil.mapToBean(map, PayBackBase.class, true, null);
        String sign = payBackBase.getSign();
        String content = getPayBackSignContent(payBackBase);
        signVerify(getPayConfig(), content, sign);
        return JSONUtil.toBean(payBackBase.getBizContent(), PayBackBizContent.class).toMap();
    }

    private String getPayBackSignContent(PayBackBase payBackBase) {
        try {
            return new URI(getPayConfig().getNotifyUrl()).getPath() + "?" + payBackBase.signIgnore().toKvStr();
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
    }


    private <R> R execute(ParamSign paramSign, TransactionType transactionType, Class<R> clazz) {
        String signStr = transactionType.uri() + "?" + paramSign.toKvStr();
        ParamSign signParamSign = paramSign.sign(createSign(signStr));
        HttpParam<ParamSign> param = new HttpParam<>(signParamSign, transactionType)
                .addHeader(VERSION_HEADER_NAME, VERSION);
        BaseRes res = payRequestTemplate.execute(param, BaseRes.class);
        String content = res.getResponseBizContent();
        signVerify(getPayConfig(), content, res.getSign());
        return JSONUtil.toBean(content, clazz);
    }

}
